package com.gaojinqi.sys.core.shiro.config;

import com.gaojinqi.sys.config.properties.ShiroAuthProperties;
import com.gaojinqi.sys.core.shiro.filter.JwtFilter;
import com.gaojinqi.sys.core.shiro.realm.AonModularRealmAuthenticator;
import com.gaojinqi.sys.core.shiro.realm.JwtRealm;
import com.gaojinqi.sys.core.shiro.realm.UsernamePasswordRealm;
import com.gaojinqi.sys.core.shiro.rest.RestShiroFilterFactoryBean;
import com.gaojinqi.sys.core.shiro.token.JwtToken;
import com.google.common.collect.Maps;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.Authorizer;
import org.apache.shiro.authz.ModularRealmAuthorizer;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.gaojinqi.sys.core.shiro.matcher.JwtCredentialsMatcher;

import javax.servlet.Filter;
import java.util.List;
import java.util.Map;

/**
 * shiro 配置
 *
 * @author gaojinqi
 * @version 1.0
 * @since 2020年04月17日
 */
@Configuration
@EnableConfigurationProperties(value = ShiroAuthProperties.class)
public class ShiroConfiguration {

    @Autowired(required = false)
    private CacheManager cacheManager;
    @Autowired
    private ShiroAuthProperties shiroAuthProperties;

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(
            SecurityManager securityManager, ShiroFilterConfiguration filterConfig,
            JwtFilter jwtFilter) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new RestShiroFilterFactoryBean();
        // 设置 securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 登录的 url
        //shiroFilterFactoryBean.setLoginUrl(shiroAuthProperties.getLoginUrl());
        // 登录成功后跳转的 url
        //shiroFilterFactoryBean.setSuccessUrl(shiroAuthProperties.getLoginSuccessUrl());
        // 未授权 url
        //shiroFilterFactoryBean.setUnauthorizedUrl(shiroAuthProperties.getUnauthorizedUrl());
        // 设置过滤器链
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterConfig.getFilterChainDefinitionMap());
        // 设置过滤器
        Map<String, Filter> filtersMap = Maps.newLinkedHashMap();
        filtersMap.put(JwtFilter.FILTER_NAME, jwtFilter);
        shiroFilterFactoryBean.setFilters(filtersMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager(List<Realm> realms) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setAuthenticator(new AonModularRealmAuthenticator());
        securityManager.setRealms(realms);
        securityManager.setCacheManager(cacheManager);
        // 无状态subjectFactory设置
        DefaultSessionStorageEvaluator evaluator = (DefaultSessionStorageEvaluator) ((DefaultSubjectDAO) securityManager.getSubjectDAO()).getSessionStorageEvaluator();
        evaluator.setSessionStorageEnabled(Boolean.FALSE);
        StatelessWebSubjectFactory subjectFactory = new StatelessWebSubjectFactory();
        securityManager.setSubjectFactory(subjectFactory);
        //SecurityUtils.setSecurityManager(securityManager);
        return securityManager;
    }

    @Bean
    public JwtRealm jwtRealm() {
        JwtRealm realm = new JwtRealm();
        realm.setAuthenticationTokenClass(JwtToken.class);
        realm.setCredentialsMatcher(jwtCredentialsMatcher());
        return realm;
    }

    @Bean
    public JwtCredentialsMatcher jwtCredentialsMatcher() {
        return new JwtCredentialsMatcher();
    }

    /**
     * 用户名密码 - Realm
     */
    @Bean
    public UsernamePasswordRealm userAuthRealm() {
        UsernamePasswordRealm realm = new UsernamePasswordRealm();
        realm.setCredentialsMatcher(hashedCredentialsMatcher());
        realm.setAuthenticationTokenClass(UsernamePasswordToken.class);
        return realm;
    }

    /**
     * 用户名密码 - 凭证匹配器
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");   //散列算法
        hashedCredentialsMatcher.setHashIterations(2);          //散列的次数
        return hashedCredentialsMatcher;
    }

    /**
     * 解决 shiro-starter 找不到 authorizer 冲突
     */
    @Bean
    public Authorizer authorizer() {
        ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer();
        return authorizer;
    }

}
